home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
cut.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
20KB
|
869 lines
/*
* $Id: cut.c,v 0.91 1994/02/20 00:53:03 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Purpose:
* Cut & Paste. If C&P is done across images, the resulting
* image will be in RGB.
*
*/
#if !defined(lint) && defined(F_ID)
char *id_cp = "$Id: cut.c,v 0.91 1994/02/20 00:53:03 zhao Pre-Release $";
#endif
#include "bit.h"
#include "extern.h"
#include "dmalloc.h"
/********************* Cut buffer definations ****************/
typedef struct
{
int w, h; /* dumenion of cut */
void *buf; /* the matrix */
void *rasbuf; /* the raster */
}
cpbuf_t;
/*************** Local variables ************************/
static int empty; /* if a buffer available */
static int wd = 100, ht = 40; /* cut size */
static int xi, yi; /* lower-left corner */
static int bcolor = 1; /* rubber band color */
static int overwrite = 1; /* operation mode. O_MASK other */
static int cp_preview;
static int cp_readscr;
static IPTR cim;
static cpbuf_t cbuf; /* current cut buffer */
/************************************************************
* A new cut buffer is availble, save it
*************************************************************/
static void
set_cut_buf(cpbuf_t * buf, int h, int w, void *mat)
{
if (!mat || !buf)
return;
free_mat(buf->buf);
buf->buf = mat;
buf->rasbuf = ((char **) mat)[0];
buf->w = w;
buf->h = h;
empty = 0;
}
/*****************************************************************
* Release all memory used by cut buffer buf
****************************************************************/
static void
remove_cut_buf(cpbuf_t * buf)
{
if (buf)
{
free_mat(buf->buf);
buf->buf = 0;
buf->w = buf->h = 0;
empty = 1;
}
}
/***************************************************************
* Undo: for both c&p and scp
**************************************************************/
static int lpxi, lpyi, lpw, lph;/* last pasted position */
static void **undobuf; /* the undo buffer */
static void
cp_undo(IPTR im)
{
long owin = winget();
if (lpw > 0 && lph > 0 && undobuf)
{
set_current_window(win_id);
Rectwrite(lpxi, lpyi, lpxi + lpw - 1, lpyi + lph - 1, undobuf[0]);
put_subimage(im, undobuf, make_rect(lpxi, lpyi, lpw, lph), 1);
lpw = lph = 0;
free_mat(undobuf);
undobuf = 0;
set_current_window(owin);
}
}
/**************** local and GUI functions ****************/
static int cp_init(IPTR, int); /* initialization */
static void cp_cut(IPTR); /* cut */
static void cp_paste(IPTR); /* paste */
static int cp_keybd(IPTR, int); /* keyboard input handler */
static void cp_undo(IPTR);
static void cp_move(IPTR);
static void cp_no_buf(IPTR);
static void re_size_region(int *, int *, int *, int *, int);
static void create_form_cp(void);
static FL_FORM *cp;
static FL_OBJECT *br, *bufname;
/************************************************************
* The global entry point
************************************************************/
int
do_cut_paste(IPTR im)
{
short val;
int lw = wd, lh = ht, cpdone = 0;
long dev;
if (cp_init(im, 0) < 0)
return -1;
set_rubber_obj(RB_RECT);
/* how to handle window manager re-position/resize events */
install_wm_handler(cp_init);
cim = im;
empty = 1;
create_form_cp();
bit_show_form(cp, FL_PLACE_MOUSE, 0, "Cut & Paste");
do
{
set_cursor(win_id, empty ? CUR_DEFAULT : CUR_S_FRECT);
dev = rubber_cursor(win_id, &val, &xi, &yi, wd, ht,
(show_cut_buffer && !empty) ? 0 : bcolor);
cp_move(im);
switch (bit_handle_event(dev, val))
{
case MIDDLEMOUSE:
if (val)
cp_paste(im);
break;
case LEFTMOUSE:
if (val)
cp_cut(im);
break;
case MENUBUTTON:
if (val)
{
reset_cursor(win_id);
re_size_region(&xi, &yi, &wd, &ht, bcolor);
if (lw != wd || lh != ht)
{
cp_no_buf(im);
lw = wd;
lh = ht;
}
}
break;
case UPARROWKEY:
if (val)
cp_keybd(im, 'k');
break;
case DOWNARROWKEY:
if (val)
cp_keybd(im, 'j');
break;
case LEFTARROWKEY:
if (val)
cp_keybd(im, 'h');
break;
case RIGHTARROWKEY:
if (val)
cp_keybd(im, 'l');
break;
case KEYBD:
cpdone = cpdone || cp_keybd(im, val);
break;
}
}
while (!cpdone);
/* clean up */
bit_hide_form(cp);
remove_wm_handler(cp_init);
set_current_window(win_id);
rubber_finish();
cp_no_buf(im);
/*
* need to reset to none. other routines might need to use sub_mat
* routine
*/
set_mat_op(O_NONE);
return 0;
}
/***********************************************************
* set the region that is c&p'able, taking into account
* options: if operation is not overwrite, regions outside
* the image is NOT c&p'able
**********************************************************/
static void
set_bounds(IPTR ip)
{
int xb1 = Min(ip->xi, 0), xb2 = Max(ip->xf, win_w);
int yb1 = Min(ip->yi, 0), yb2 = Max(ip->yf, win_h);
if (cp_preview && cp_readscr && overwrite == 1)
set_rubber_bounds(1, xb1, yb1, xb2, yb2);
else
set_rubber_bounds(1, ip->xi, ip->yi, ip->w, ip->h);
}
/************************************************************
* Set initial size.
********************************************************/
/*ARGSUSED*/
static int
cp_init(IPTR ip, int wme)
{
set_current_window(win_id);
rectzoom(1.0, 1.0);
xi = ip->xi + (ip->w - wd) / 2;
yi = ip->yi + (ip->h - ht) / 2;
set_rubber_center(0);
set_mat_op(overwrite ? O_NONE : O_MASK);
set_bounds(ip);
return 0;
}
/********************************************************
* for precise placement, keyboard is better. Also if ESC
* is pressed, return 1 to signify done
********************************************************/
static int
cp_keybd(IPTR im, int val)
{
int quit = 0;
int oh = ht, ow = wd;
static int step = 1;
switch (val)
{
case 27: /* esc: */
quit = 1;
break;
case 'c':
case 'C': /* cut */
cp_cut(im);
break;
case 'p':
case 'P': /* paste */
cp_paste(im);
break;
case 'u':
case 'U':
cp_undo(im);
break;
case 'x':
wd -= step;
break;
case 'X':
wd += step;
break;
case 'y':
ht -= step;
break;
case 'Y':
ht += step;
break;
case 'h':
case 'l':
case 'j':
case 'k':
if (val == 'h')
xi -= step;
if (val == 'l')
xi += step;
if (val == 'j')
yi -= step;
if (val == 'k')
yi += step;
set_mouse(xi + win_xo, yi + win_yo);
break;
default:
if (val > '0' && val <= '9')
step = val - '0';
break;
}
/* if size changes, invalidate the cut buffer */
if (!(oh == ht && ow == wd))
cp_no_buf(im);
/* do a final check to make rubber within bounds */
rubber_moveto(&xi, &yi, &wd, &ht);
return quit;
}
/********************************************************
* import an external image as a cut buffer.
********************************************************/
static void
cp_import(const char *fname)
{
IPTR im;
int oreport = report_level;
report_level = -1; /* suppress reporting */
show_busy("Importing ...");
if ((im = load_image(fname)))
{
/* need to convert both to CPACK */
if (!IS_CPACK(cim))
{
img_convert_type(cim, T_RGBA);
cim->io->display(cim, 0, 0);
}
img_convert_type(im, T_RGBA);
set_cut_buf(&cbuf, ht = im->h, wd = im->w, im->mraster);
fl_set_object_label(bufname, "Imported");
im->mraster = im->raster = 0;
if (im->type != cim->type) /* only if rgb & graq */
cim->type = T_RGBA;
}
free_image(im);
report_level = oreport;
end_busy();
}
static void
cp_move(IPTR im)
{
static int lxi, lyi;
if (show_cut_buffer && !empty)
{
if (double_buf)
{
PI_rectwrite(xi, yi, xi + wd - 1, yi + ht - 1, cbuf.rasbuf);
swapbuffers();
img_rect_redraw(im, lxi, lyi, wd, ht);
}
else
{
sim_dbl_swap(im, wd, ht, cbuf.buf, xi, yi, lxi, lyi, O_NONE);
}
lxi = xi;
lyi = yi;
}
}
/********************************************************
* Change C&P size. Block until a unknown key in entered
*******************************************************/
static void
re_size_region(int *x, int *y, int *w, int *h, int col)
{
long dev;
short val;
do
{
dev = rubber_info(win_id, &val, x, y, w, h, col, 15);
}
while (handle_const_q(dev, val) == 0);
rubber_finish();
}
static int ncpbuf;
int
no_of_cut_paste_buffers(void)
{
return (!cp || (ncpbuf = fl_get_browser_maxline(br)) <= 0) ?
0 : ncpbuf;
}
const char *
cut_paste_buffer_name(int i)
{
int j = i + 1;
return (j < 1 || j > ncpbuf) ? 0 :
fl_get_browser_line(br, j);
}
static void
stop_at_first_space(char name[])
{
char *p = strchr(name, ' ');
if (p)
*p = '\0';
}
/****************************************************************
* remove all buffers. Global cleanup
*****************************************************************/
void
cleanup_cut_paste(void)
{
int i, imax;
char name[1024];
if (!cp || (imax = fl_get_browser_maxline(br)) <= 0)
return;
fl_freeze_form(cp);
for (i = 1; i <= imax; i++)
{
strcpy(name, fl_get_browser_line(br, i));
stop_at_first_space(name);
(void) remove(get_TMPfile(name));
}
fl_clear_browser(br);
fl_unfreeze_form(cp);
ncpbuf = 0;
}
/*******************************************************
* save the current region and put the cut into un-named
* buffer
********************************************************/
static void
cp_cut(IPTR im)
{
if (wd == 0 || ht == 0)
return;
show_busy("");
set_current_window(win_id);
if (cp_readscr)
{
set_cut_buf(&cbuf, ht, wd, get_mat(ht, wd, im->esize));
Rectread(xi, yi, xi + wd - 1, yi + ht - 1, cbuf.rasbuf);
}
else
{
set_cut_buf(&cbuf, ht, wd, get_subimage(im, xi, yi, wd, ht));
}
fl_set_object_label(bufname, "unnamed");
end_busy();
}
/***************************************************************
* paste the cut buffer. If commit flag is on, change the raster
* as well
***************************************************************/
static void
cp_paste(IPTR im)
{
int lx = 0, ly = 0;
if (empty)
return;
rubber_hide();
set_current_window(win_id);
if (cbuf.h != ht || cbuf.w != wd)
{
M_err("Paste", "something is wrong ");
return;
}
do
{
get_mouse_r2w(&xi, &yi);
rubber_moveto(&xi, &yi, &wd, &ht); /* checking position */
if (lx != xi || ly != yi)
{
/* save for possible undo */
lpw = wd;
lph = ht;
undobuf = no_fail_get_subimage(im, xi, yi, wd, ht);
if (!cp_preview)
{
put_subimage(im, cbuf.buf, make_rect(xi, yi, wd, ht), 1);
}
/*
* can't simply use Rectwrite, because of possibility of
* Masking option. Write from the image
*/
dbl_rect_redraw(im, xi, yi, wd, ht);
lx = lpxi = xi;
ly = lpyi = yi;
}
}
while (getbutton(MIDDLEMOUSE));
}
/*******************************************************
* A name for buffer is entered, save it so
*****************************************************/
/* ARGSUSED */
static void
save_buf(FL_OBJECT * ob, long l)
{
rgba_t *tmp, *tend;
ci_t *ci;
CMPTR m = cim->cmap;
FILE *fp;
char line[50], size[50], *p;
int i, imax = fl_get_browser_maxline(br), k = -1;
long total = cbuf.w * cbuf.h;
const char *pp;
if (empty || !(pp = getstring("Buffername", "", 1)) || !*pp)
return;
Strncpy(line, pp, sizeof(line));
/* remove all spaces */
i = 0;
while (line[i])
{
if (line[i] == ' ')
line[i] = '_';
i++;
}
for (i = 1; i <= imax && k < 0; i++)
{
Strncpy(size, fl_get_browser_line(br, i), sizeof(size));
if ((p = strchr(size, ' ')))
*p = 0;
if (strcmp(line, size) == 0)
{
k = i;
}
}
if (k > 0)
{
if (!yes_no("Warning",
"Buffer by the same name already exits", "Overwrite ?", 0))
return;
}
show_busy("SaveCutBuf ...");
if (IS_CI(cim))
{
tmp = malloc(sizeof(rgba_t) * total);
ci = cbuf.rasbuf;
for (tend = tmp + total; tmp < tend; tmp++, ci++)
{
*ci &= PCMAXV;
*tmp = Pack(m->ct[0][*ci], m->ct[1][*ci], m->ct[2][*ci]);
}
tmp = tend - total;
}
else
{
tmp = cbuf.rasbuf;
}
if (!(fp = get_TMPfile_fp(line, "w")))
return;
put2LSBF(cbuf.w, fp);
put2LSBF(cbuf.h, fp);
if (Badfwrite(tmp, sizeof(rgba_t), total, fp))
{
Bark("SaveBuf", "Bad Write");
}
fclose(fp);
sprintf(size, " (%dX%d)", cbuf.w, cbuf.h);
strncat(line, size, sizeof(line) - 1);
if (k < 0)
fl_add_browser_line(br, line);
else
fl_replace_browser_line(br, k, line);
if (tmp != cbuf.rasbuf)
free(tmp);
end_busy();
}
/*************************************************************************
* a named buffer is selected
*************************************************************************/
/* ARGSUSED */
static void
load_buf(FL_OBJECT * ob, long l)
{
int i;
char name[120];
FILE *fp;
long total;
if ((i = fl_get_browser(br)) <= 0)
return;
Strncpy(name, fl_get_browser_line(br, i), sizeof(name));
stop_at_first_space(name);
/* read from disk */
if (!(fp = get_TMPfile_fp(name, "r")))
return;
cbuf.w = get2LSBF(fp);
cbuf.h = get2LSBF(fp);
if ((total = cbuf.w * cbuf.h) <= 0)
{
Bark("ReadBuf", "%s: Bad size w=%d h=%d", name, wd, ht);
empty = 1;
return;
}
empty = 0;
show_busy("LoadCutBuf ...");
free_mat(cbuf.buf);
cbuf.buf = 0;
cbuf.buf = get_mat(cbuf.h, cbuf.w, sizeof(rgba_t));
cbuf.rasbuf = ((rgba_t **) cbuf.buf)[0];
if (Badfread(cbuf.rasbuf, sizeof(rgba_t), total, fp))
{
Bark("ReadBuf", "%s: Bad read", name);
empty = 1;
}
fclose(fp);
/* need to convert the image to RGB if it's not already */
wd = cbuf.w;
ht = cbuf.h;
if (!empty)
{
fl_set_object_label(bufname, name);
if (!IS_CPACK(cim))
{
show_busy("Converting to RGB ...");
img_convert_type(cim, T_RGBA);
cim->io->display(cim, 0, 0); /* display will reset cursor */
}
}
end_busy();
}
/* ARGSUSED */
static void
import_cb(FL_OBJECT * ob, long q)
{
const char *imfile;
if ((imfile = getfilename("ImportFile", ".", "*.*", "", 1)))
cp_import(imfile);
}
/* ARGSUSED */
static void
del_buf(FL_OBJECT * ob, long l)
{
int i = fl_get_browser(br);
char line[50], *p;
if (i <= 0)
return;
Strncpy(line, fl_get_browser_line(br, i), sizeof(line));
if ((p = strchr(line, ' ')))
*p = '\0';
(void) remove(get_TMPfile(line));
fl_delete_browser_line(br, i);
}
/* ARGSUSED */
static void
del_all_buf(FL_OBJECT * ob, long l)
{
cleanup_cut_paste();
}
/* ARGSUSED */
static void
finish_cp(FL_OBJECT * obj, long l)
{
set_mat_op(O_NONE);
fl_qenter(KEYBD, 27);
}
/* ARGSUSED */
static void
set_cut_source(FL_OBJECT * ob, long q)
{
cp_readscr = fl_get_choice(ob) == 1;
set_bounds(cim);
}
/* ARGSUSED */
static void
set_cp_mode(FL_OBJECT * ob, long l)
{
overwrite = fl_get_choice(ob) == 1;
set_bounds(cim);
set_mat_op(overwrite ? O_NONE : O_MASK);
}
/*ARGSUSED */
static void
set_cp_op(FL_OBJECT * ob, long q)
{
cp_preview = fl_get_choice(ob) == 1;
set_bounds(cim);
}
/* Short cuts to carry out control panel requests */
typedef struct
{
const char *name;
void (*cb) (FL_OBJECT *, long);
int bcolor;
}
cbbuf_;
/* ARGSUSED */
static void
undo_paste(FL_OBJECT * ob, long q)
{
cp_undo(imgptr);
}
static cbbuf_ cbbuf[] =
{
{"Import", import_cb, FL_GREEN},
{"Save", save_buf, FL_GREEN},
{"Undo", undo_paste, FL_GREEN},
{"Delete", del_buf, FL_YELLOW},
{"DelAll", del_all_buf, FL_RED},
{0, 0, 0}
};
/********************************************************************
* Remove last buffer
*******************************************************************/
static void
cp_no_buf(IPTR im)
{
if (!empty)
{
if (show_cut_buffer)
{
#ifndef SGL_BUF
if (double_buf)
swapbuffers();
#endif
img_rect_redraw(im, xi, yi, wd, ht);
}
reset_cursor(win_id);
remove_cut_buf(&cbuf);
}
}
static void
create_form_cp(void)
{
FL_OBJECT *obj;
static int ok;
float x, y, dx, dy;
cbbuf_ *aa = cbbuf;
if (ok)
return;
cp = fl_bgn_form(FL_NO_BOX, 260.0, 280.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 260.0, 280.0, "");
fl_set_object_color(obj, 9, 47);
obj = fl_add_button(FL_HB, 0, 0, 260, 280, "");
fl_set_call_back(obj, help_cb, HELP_CP);
br = obj = fl_add_browser(FL_HBR, 10.0, 15.0, 150.0, 205.0, "");
fl_set_object_boxtype(obj, FL_SHADOW_BOX);
fl_set_object_color(obj, 9, 3);
fl_set_browser_fontsize(obj, 10.0);
fl_set_call_back(obj, load_buf, 0);
bufname = obj = fl_add_text(FL_NT, 170.0, 195.0, 80.0, 25.0, "");
fl_set_object_boxtype(obj, FL_BORDER_BOX);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
fl_set_object_label(obj, "None");
x = 170.0;
y = 160.0;
dx = 80.0;
dy = 25.0;
while (aa && aa->name)
{
obj = fl_add_button(FL_NB, x, y, dx, dy, aa->name);
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, aa->bcolor);
fl_set_call_back(obj, aa->cb, 0);
aa++;
y -= dy;
}
y = 10;
obj = fl_add_button(FL_NB, x, y, dx, dy, "Done");
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, finish_cp, 0);
/* options */
obj = fl_add_choice(FL_NC, 10.0, 240.0, 80.0, 25.0, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontstyle(obj, FL_BOLD_STYLE);
fl_set_choice_fontsize(obj, 10.0);
fl_addto_choice(obj, "Preview");
fl_addto_choice(obj, "Commit");
fl_set_choice(obj, cp_preview ? 1 : 2);
fl_set_call_back(obj, set_cp_op, 0);
obj = fl_add_choice(FL_NORMAL_CHOICE, 170.0, 240.0, 80.0, 25.0, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontstyle(obj, FL_BOLD_STYLE);
fl_set_choice_fontsize(obj, 10.0);
fl_addto_choice(obj, "Overwrite");
fl_addto_choice(obj, "Mask");
fl_set_choice(obj, overwrite ? 1 : 2);
fl_set_call_back(obj, set_cp_mode, 0);
obj = fl_add_choice(FL_NORMAL_CHOICE, 90.0, 240.0, 80.0, 25.0, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontstyle(obj, FL_BOLD_STYLE);
fl_set_choice_fontsize(obj, 10.0);
fl_addto_choice(obj, "ReadScr");
fl_addto_choice(obj, "Internal");
fl_set_choice(obj, cp_readscr ? 1 : 2);
fl_set_call_back(obj, set_cut_source, 0);
ok = 1;
fl_end_form();
}